package com.gee.spring.cloud.data.transform.core.util;

import cn.hutool.crypto.digest.DigestUtil;
import com.gee.spring.cloud.data.transform.core.dsl.DslCompileConfig;
import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @author gepengjun
 * @since 2022/12/1 13:47
 */
public class DslUtil {

    private static final ConcurrentHashMap<String, Class<?>> groovyClassCacheMap = new ConcurrentHashMap<>();

    private static final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(getParentLoader(), DslCompileConfig.getInstance());

    public static Object invokeStatic(String methodName ,String scriptStr, Object ... args){
        String groovyClassName = generateGroovyClassName(scriptStr);
        Class<?> groovyClass = groovyClassCacheMap.computeIfAbsent(groovyClassName, s -> groovyClassLoader.parseClass(scriptStr));
        return InvokerHelper.invokeStaticMethod(groovyClass, methodName, args);
    }


    private static String generateGroovyClassName(String scriptStr){
        return "Script_" + DigestUtil.md5Hex(scriptStr).toLowerCase();
    }

    private static ClassLoader getParentLoader() {
        // check whether thread context loader can "see" Groovy Script class
        ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
        try {
            Class<?> c = ctxtLoader.loadClass(Script.class.getName());
            if (c == Script.class) {
                return ctxtLoader;
            }
        } catch (ClassNotFoundException cnfe) {
            /* ignore */
        }
        // exception was thrown or we get wrong class
        return Script.class.getClassLoader();
    }
}
